// CHAPTER 4 OF OBJECT ORIENTED JAVASCRIPT
// OBJECTS
mainchapter("4 OBJECTS");

(function(){
	// 4.1 Elements Properties Methods
	chapter("4.1 Elements, Properties, Methods");
	try{
		var hero = {
			breed: 'Turtle',
			occupation: 'Ninja'
		};
		assertEquals(hero.breed,'Turtle');
		success("4.1.1a Simple access properties (object.prop notation)");
		assertEquals(hero["occupation"],'Ninja');
		success("4.1.1b Simple access properties (object['prop'] notation)");
		var testprop = {
			normal : "normal",
			'squoted' : "squoted",
			"dquoted" : "dquoted"
		}
		assertEquals(testprop.normal,"normal");
		assertEquals(testprop.squoted,"squoted");
		assertEquals(testprop.dquoted,"dquoted");
		success("4.1.1c Single/double quoted properties");
		var dog = {
			name : 'Benji',
			talk : function() {
				return "woof";
			}
		};
		assertEquals(dog.talk(),"woof");
		assertEquals(dog["talk"](),"woof");
		success("4.1.1d Function as an object property");
		var book = {
			name: 'Catch-22',
			published: 1961,
			author: {
				firstname: 'Joseph',
				lastname: 'Heller'
			}
		}
		assertEquals(book.author.lastname,"Heller");
		assertEquals(book["author"]["lastname"],"Heller");
		assertEquals(book["author"].lastname,"Heller");
		success("4.1.1e Object as Property of an Object");
	}catch(e){
		$ERROR("4.1.1 Accessing Elements, Properties, Methods : "+e.message);
	}
	try{
		var hero = {};
		assertEquals(typeof hero.breed,"undefined");
		hero.breed = 'turtle';
		hero.name = 'Leonardo';
		hero.sayName = function(){return hero.name;};
		assertEquals(hero.sayName(),"Leonardo");
		assertEquals(delete hero.name,true);
		success("4.1.2a Deleted a property");
		assertEquals(hero.sayName(),undefined);
		success("4.1.2b Function that returned a deleted property gives undefined");
	}catch(e){
		$ERROR("4.1.2 Altering Elements, Properties, Methods : "+e.message);
	}
})();

(function(){
	// 4.2 CONSTRUCTOR FUNCTIONS
	chapter("4.2 CONSTRUCTOR FUNCTIONS");
	try{
		function Hero(name){
			this.occupation = 'Ninja';
			this.name = name;
			this.whoareyou = function(){
				return this.name;
			}
		}
		var hero = new Hero("Sam");
		assertEquals(hero.occupation,'Ninja');
		success("4.2a can construct an object and access property");
		assertEquals(hero.name,'Sam');
		assertEquals(hero.whoareyou(),'Sam');
		success("4.2b can construct object with param and access it");
		assertEquals(typeof hero,"object");
		success("4.2c The constructed object is typeof object");
		//var h = Hero("Andy");
		//assertEquals(this.name,"Andy");
		$ERROR("NARCISSUS crashes when calling constructor without new keyword (when using this.property and accessing the global scope)");
	}catch(e){
		$ERROR("4.2 Error with constructor : "+e.message);
	}
})();

(function(){
	// 4.3 INSTANCEOF OPERATOR
	chapter("4.3 INSTANCEOF OPERATOR");
	try{
		function Hero(){}
		var inst_hero = new Hero();
		var inst_o = {};
		assertEquals(inst_hero instanceof Hero,true,"hero must be an instance of a Hero");
		success("4.3a The var hero is a Hero");
		assertEquals(inst_o instanceof Object,true,"{} is an Object");
		success("4.3b {} is an Object");
		// FAILS IN IE,FF(spidermonkey) TOO
		assertEquals(inst_hero instanceof Object,false,"The var hero must not be an Object");
		success("4.3c The var hero is not an Object");
	}catch(e){
		$ERROR("4.3 INSTANCEOF OPERATOR : "+e.message);
	}
})();

(function(){
	// 4.4 FUNCTIONS THAT RETURN OBJECTS
	chapter("4.4 FUNCTIONS THAT RETURN OBJECTS");
	try{
		function factory(name){
			return {
				name: name
			};
		}
		var o = factory('one');
		assertEquals(o.name,'one');
		success("4.4a Object factory");
		function C(){this.a = 1; return {b: 2};}
		var c = new C();
		assertEquals(typeof c.a, "undefined");
		assertEquals(c.b, 2);
		success("4.4b Constructor returns object");
	}catch(e){
		$ERROR("4.4 FUNCTIONS THAT RETURN OBJECTS : "+e.message);
	}
})();

(function(){
	// 4.5 PASSING OBJECTS
	chapter("4.5 PASSING OBJECTS");
	try{
		var original = {howmany: 1};
		var copy = original;
		assertEquals(original.howmany,1);
		copy.howmany = 100;
		assertEquals(copy.howmany,100);
		assertEquals(original.howmany,100);
		success("4.5a Passing object by reference in a call");
		var original = {howmany: 100};
		var nullify = function(o){o.howmany = 0;}
		assertEquals(original.howmany,100);
		nullify(original);
		assertEquals(original.howmany,0);
		success("4.5b Editing a referenced object in a function");
	}catch(e){
		$ERROR("4.5 PASSING OBJECTS : "+e.message);
	}
})();

(function(){
	// 4.6 COMPARING OBJECT
	chapter("4.6 COMPARING OBJECT");
	try{
		var fido = {breed: 'dog'};
		var benji = {breed: 'dog'};
		assertEquals(fido === benji,false);
		assertEquals(fido == benji,false);
		var mydog = benji;
		assertEquals(mydog === benji,true);
		assertEquals(fido === mydog,false);
		success("4.6 Comparing objects is by reference ===");
	}catch(e){
		$ERROR("4.6 COMPARING OBJECT : "+e.message);
	}
})();


(function(){
	// 4.7 BUILTIN OBJECTS
	chapter("4.7 BUILTIN OBJECTS");
	try{
		var o = new Object();
		assertEquals(o.valueOf(),o);
		assertEquals(typeof o.toString,"function");
		success("4.7.1 Object has valueOf, toString");
	}catch(e){
		$ERROR("4.7.1 Object OBJECT : "+e.message);
	}
	try{
		var a = new Array();
		a[0] = 1; a[1] = 2;
		assertEquals(a[0],1);
		assertEquals(a[1],2);
		var a2 = new Array(1,2,3,'four');
		success("4.7.2a construct Array");
		assertEquals(a2[0],1);
		assertEquals(a2[1],2);
		assertEquals(a2[3],'four');
		assertEquals(a2.toString(),'1,2,3,four');
		assertEquals(typeof a2.constructor,"function");
		assertEquals(a2.length,4,"Array.length");
		success("4.7.2b Array.length");
		a2.length=5;
		assertEquals(a2[4],undefined,"Array.length");
		a2.push("six");
		assertEquals(a2[5],"six","Array.push");
		success("4.7.2c Array.push");
		var a3 = a2.slice(1,3);
		assertEquals(a3.length,2);
		assertEquals(a3[1],3);
		success("4.7.2d Array.slice");
	}catch(e){
		$ERROR("4.7.2 ARRAY OBJECT : "+e.message);
	}	
	try{
		assertEquals(Math.PI>3,true,"Math.PI is not set: "+Math.PI);
		assertEquals(Math.round(Math.PI*100)/100,3.14,"Math.PI wrong value: "+Math.PI);
		success("4.7.3a Math.PI, Math.round");
		assertEquals(Math.round(Math.E*100)/100,2.72);
		success("4.7.3b Math.E");
		assertEquals(Math.round(Math.LN10*100)/100,2.30);	
		success("4.7.3c Math.LN10");
		assertEquals(Math.random() > 0,true);
		success("4.7.3d Math.random");
		assertEquals(Math.pow(2,8),256);
		success("4.7.3e Math.pow");
	}catch(e){
		$ERROR("4.7.3 Math obj : "+e.message);
	}
	try{
		var re = new RegExp('j.*t','gmi');
		var re2 = /j.*t/;
		success("4.7.4a Create RegExp");
		assertEquals(re.global,true);
		re.global = false;
		assertEquals(re.global,true);
		success("4.7.4b RegExp.global");
		assertEquals(re.test("Javascript"),true);
		assertEquals(/j.*t/.test("Javascript"),false); // case sensitive
		success("4.7.4c RegExp.test");
		var s = new String('HelloJavaScriptWorld');
		assertEquals(s.match(/a/g).length,2);
		assertEquals(s.match(/j.*a/i)[0],"Java");
		success("4.7.4d String Match with regexp");
		assertEquals(s.search(/j.*a/i),5);
		success("4.7.4e String Search with regexp");
		assertEquals(s.replace(/[A-Z]/g,""),'elloavacriptorld');
		assertEquals(s.replace(/[A-Z]/,""),'elloJavaScriptWorld');
		success("4.7.4e String Replace with regexp");
	}catch(e){
		$ERROR("4.7.4 RegExp : "+e.message);
	}
})();

(function(){
	// 4.8 APPLY / CALL functions
	chapter("4.8 APPLY / CALL functions");
	try{
		var some_obj = {
			name:'Ninja',
			say: function(who){
				return "Hey " + who + ", I am a "+this.name;
			}
		}
		assertEquals(some_obj.say("Dude"),"Hey Dude, I am a Ninja");
		my_obj = {name: 'Guru'};
		assertEquals(some_obj.say.call(my_obj,"Dude"),"Hey Dude, I am a Guru");
		success("4.8.1 some_obj.function.call");
		assertEquals(some_obj.say.apply(my_obj,["Dude"]),"Hey Dude, I am a Guru");
		success("4.8.1 some_obj.function.apply");
	}catch(e){
		$ERROR("4.8 APPLY / CALL : "+e.message);
	}
})();

(function(){
	// 4.9 Try/Catch/Finally
	chapter("4.9 Try/Catch/Finally");
	try{
		success("4.9a try executed");
		throw new Error("Error thrown");
		$ERROR("4.9b no exception was thrown after calling undefined method");
	}catch(e){
		success("4.9b catch executed after error : "+e.message);
	}finally{
		success("4.9c finally executed");
	}
})();





